package top.mypath.service;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson2.JSON;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import top.mypath.model.MaxOrderCombine;
import top.mypath.model.Order;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author LiYalin
 */
@Slf4j
public class SplitService {
    private static BigDecimal quota=new BigDecimal(113000);

    public static BigDecimal getQuota() {
        return quota;
    }

    public static void setQuota(BigDecimal quota) {
        SplitService.quota = quota;
    }




    public static List<MaxOrderCombine> splitData(List<Order> cachedDataList){
        List<Order> maxList = cachedDataList.stream().filter(order -> order.getTotal().compareTo(quota) > -1).collect(Collectors.toList());
        List<Order> operationList = cachedDataList.stream().filter(order -> order.getTotal().compareTo(quota) < 0).sorted(Comparator.comparing(Order::getTotal).reversed()).collect(Collectors.toList());
        log.info("maxList:"+ JSON.toJSONString(maxList));
        log.info("operationList:"+JSON.toJSONString(operationList));
        List<MaxOrderCombine> finalOrderCombines = maxList.stream().map(order -> {
            MaxOrderCombine maxOrderCombine = new MaxOrderCombine();
            List<String> initBatchNumbers = new ArrayList<>();
            initBatchNumbers.add(order.getBatchNumber());
            maxOrderCombine.setBatchNumbers(initBatchNumbers);
            maxOrderCombine.setTotal(order.getTotal());
            maxOrderCombine.setNum(1);
            return maxOrderCombine;
        }).collect(Collectors.toList());
        List<Order> copyOperationList = new ArrayList<>(operationList);
        while (CollectionUtil.isNotEmpty(copyOperationList)) {
            MaxOrderCombine orderCombine = find(copyOperationList);
            finalOrderCombines.add(orderCombine);
            List<String> batchNumbers = orderCombine.getBatchNumbers();
            Iterator<Order> iterator=copyOperationList.iterator();
            for(;iterator.hasNext();){
                Order next = iterator.next();
                if(batchNumbers.contains(next.getBatchNumber())){
                    iterator.remove();
                }
            }
        }
        //当前发票序号
        int invoiceNum=1;
        finalOrderCombines=finalOrderCombines.stream().sorted(Comparator.comparing(MaxOrderCombine::getTotal)).collect(Collectors.toList());
        for(int i=0;i<finalOrderCombines.size();i++){
            MaxOrderCombine orderCombine = finalOrderCombines.get(i);
            if(orderCombine.getTotal().compareTo(quota)<=0){
                orderCombine.setInvoiceSerialNumber(String.valueOf(invoiceNum));
                invoiceNum++;
            }else{
                double value = orderCombine.getTotal().doubleValue();
                int num= (int) (value%quota.intValue()>0?value/quota.intValue()+1:value/quota.intValue());
                String invoiceString="";
                for(int j=0;j<num;j++) {
                    if (StringUtils.isBlank(invoiceString)){
                        invoiceString = String.valueOf(invoiceNum);
                        invoiceNum++;
                    }else{
                        invoiceString =invoiceString+"、"+String.valueOf(invoiceNum);
                        invoiceNum++;
                    }
                }
                orderCombine.setInvoiceSerialNumber(invoiceString);
            }
        }
        log.info("最终结果："+finalOrderCombines);
        return finalOrderCombines;
    }

    /**
     * 查找最优组合
     * @param operationList 可以操作的数据
     * @return
     */
    private static MaxOrderCombine find(List<Order> operationList){
        //用于存储所有符合条件的结果
        List<MaxOrderCombine> allOrderCombines = new ArrayList<>();
        Order order = operationList.get(0);
        List<String> initBatchNumbers = new ArrayList<>();
        initBatchNumbers.add(order.getBatchNumber());
        //数据初始化
        MaxOrderCombine maxOrderCombine = new MaxOrderCombine();
        maxOrderCombine.setBatchNumbers(initBatchNumbers);
        maxOrderCombine.setTotal(order.getTotal());
        maxOrderCombine.setNum(1);
        allOrderCombines.add(maxOrderCombine);
        combine(operationList, maxOrderCombine,allOrderCombines);
        //获取到最终结果后，取最优的一个
        if(CollectionUtil.isNotEmpty(allOrderCombines)){
            MaxOrderCombine optimal = allOrderCombines.get(0);
            for(int i=1;i<allOrderCombines.size();i++){
                MaxOrderCombine temp = allOrderCombines.get(i);
                if(optimal.getTotal().compareTo(temp.getTotal())==-1){
                    optimal=temp;
                }else if(optimal.getTotal().compareTo(temp.getTotal())==0){
                    if(optimal.getNum()<temp.getNum()){
                        optimal=temp;
                    }
                }
            }
            return optimal;
        }else {
            return null;
        }
    }

    /**
     * 获取所有符合条件的组合
     * @param operationList 操作数据
     * @param maxOrderCombine 已存在的组合
     * @param allOrderCombines 所有符合条件的组合信息
     */
    private static void combine(List<Order> operationList,final MaxOrderCombine maxOrderCombine,List<MaxOrderCombine> allOrderCombines){
        BigDecimal total = maxOrderCombine.getTotal();
        List<String> batchNumbers = maxOrderCombine.getBatchNumbers();
        int num = maxOrderCombine.getNum();
        List<MaxOrderCombine> newList = new ArrayList<>();
        for(Order order:operationList){
            String batchNumber = order.getBatchNumber();
            BigDecimal orderTotal = order.getTotal();
            if(!batchNumbers.contains(batchNumber) && total.add(orderTotal).compareTo(quota)<=0){
                MaxOrderCombine newMaxOrderCombine = new MaxOrderCombine();
                List<String> tempList = new ArrayList<>(batchNumbers);
                tempList.add(order.getBatchNumber());
                if(!isExistence(tempList,allOrderCombines)) {
                    newMaxOrderCombine.setBatchNumbers(tempList);
                    newMaxOrderCombine.setTotal(total.add(orderTotal));
                    newMaxOrderCombine.setNum(num + 1);
                    newList.add(newMaxOrderCombine);
                }
            }
        }
        if(CollectionUtil.isNotEmpty(newList)){
            Optional<MaxOrderCombine> optional = newList.stream().max(Comparator.comparing(MaxOrderCombine::getTotal));
            allOrderCombines.add(optional.get());
            combine(operationList,optional.get() , allOrderCombines);
        }
    }

    private static boolean isExistence(List<String> tempList,List<MaxOrderCombine> allOrderCombines){
        return allOrderCombines.stream().anyMatch(orderCombine->orderCombine.getBatchNumbers().equals(tempList));
    }

    /**
     * 顺序数据拆分
     * @param cachedDataList
     * @return
     */
    public static List<MaxOrderCombine> orderSplitData(List<Order> cachedDataList){
        ArrayList<MaxOrderCombine> maxOrderCombines = new ArrayList<>();
        BigDecimal zero = new BigDecimal(0);
        BigDecimal total=new BigDecimal(0);
        Integer invoiceSerialNumber=1;
        MaxOrderCombine orderCombine = new MaxOrderCombine();
        for (Order order : cachedDataList) {
            BigDecimal orderTotal = order.getTotal();
            BigDecimal tempTotal = total.add(orderTotal);
            if(tempTotal.compareTo(quota) > -1){
                //如果订单金额大于发票限额，且就一张票则对该票进行单独处理
                if(total.compareTo(zero)==0){
                    MaxOrderCombine tempMaxOrderCombine = getMaxOrderCombine(invoiceSerialNumber, order);
                    maxOrderCombines.add(tempMaxOrderCombine);
                }else {
                    orderCombine.setInvoiceSerialNumber(String.valueOf(invoiceSerialNumber++));
                    maxOrderCombines.add(orderCombine);
                    //如果total不为零则证明之前有数据，将之前的数据保存，并重置临时条件
                    orderCombine = new MaxOrderCombine();
                    total = new BigDecimal(0);
                    if(orderTotal.compareTo(quota)> -1){
                        MaxOrderCombine tempMaxOrderCombine = getMaxOrderCombine(invoiceSerialNumber, order);
                        maxOrderCombines.add(tempMaxOrderCombine);
                    }else{
                        orderCombine.getBatchNumbers().add(order.getBatchNumber());
                        orderCombine.setTotal(orderCombine.getTotal().add(order.getTotal()));
                        orderCombine.setNum(orderCombine.getNum()+1);
                        total=total.add(order.getTotal());
                    }
                }
            }else {
                //继续添加下一个菜单
                orderCombine.getBatchNumbers().add(order.getBatchNumber());
                orderCombine.setTotal(orderCombine.getTotal().add(order.getTotal()));
                orderCombine.setNum(orderCombine.getNum()+1);
                total=total.add(order.getTotal());
            }
        }
        return maxOrderCombines;
    }

    private static MaxOrderCombine getMaxOrderCombine(Integer invoiceSerialNumber, Order order) {
        MaxOrderCombine maxOrderCombine = new MaxOrderCombine();
        List<String> initBatchNumbers = new ArrayList<>();
        initBatchNumbers.add(order.getBatchNumber());
        maxOrderCombine.setBatchNumbers(initBatchNumbers);
        maxOrderCombine.setTotal(order.getTotal());
        maxOrderCombine.setNum(1);
        double value = order.getTotal().doubleValue();
        int num= (int) (value%quota.intValue()>0?value/quota.intValue()+1:value/quota.intValue());
        String invoiceString="";
        for(int j=0;j<num;j++) {
            if (StringUtils.isBlank(invoiceString)){
                invoiceString = String.valueOf(invoiceSerialNumber);
                invoiceSerialNumber++;
            }else{
                invoiceString =invoiceString+"、"+String.valueOf(invoiceSerialNumber);
                invoiceSerialNumber++;
            }
        }
        maxOrderCombine.setInvoiceSerialNumber(invoiceString);
        return maxOrderCombine;
    }

}
